package com.hksj.cbm.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hksj.cbm.dto.SpaceModelDTO;
import com.hksj.cbm.entity.SpaceModel;
import com.hksj.cbm.mapper.LargeScreenBaseMapper;
import com.hksj.cbm.mapper.SpaceModelMapper;
import com.hksj.cbm.query.SpaceModelQuery;
import com.hksj.cbm.vo.LargeScreenFileVO;
import com.hksj.cbm.vo.SpaceModelVO;
import com.hksj.common.core.common.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zengke
 * @version 1.0
 * @see SpaceModelService
 * @since 2024/7/11 14:57
 */

@Service
public class SpaceModelService extends ServiceImpl<SpaceModelMapper, SpaceModel> {

    @Autowired
    private LargeScreenBaseMapper largeScreenBaseMapper;

    /**
     * 新增空间模型
     */
    @Transactional
    public String createSpaceModel(SpaceModelDTO spaceModelDTO){

        //获取当前节点的父节点路径
        String paths = spaceModelDTO.getPaths();

        //传入的节点路径不为空
        Assert.notBlank(paths,"节点路径不为空");

        //将SpaceModelDTO类型数据转为 SpaceModel 类型
        SpaceModel spaceModel = Convert.convert(SpaceModel.class, spaceModelDTO);

        //新增模型
        super.save(spaceModel);

        //当前节点的路径为 "父节点路径"+"当前节点的id"
        String currentPaths = paths + "," + spaceModel.getId();

        //设置当前节点的路径
        spaceModel.setPaths(currentPaths);

        //设置当前节点的楼栋楼层房间点位信息
        //当level=1时模型是楼栋模型  当level=2时模型是楼层模型 当level=3时模型是房间模型 当level=4时模型是点位模型
        setAdditionalInfo(spaceModel);

        //更新当前的模型
        super.updateById(spaceModel);

        return "新增成功";
    }

    /**
     * 添加空间的模型额外信息
     * @param spaceModel 空间模型实体
     */
    private void setAdditionalInfo(SpaceModel spaceModel){

        //子查父 查询父节点列表
        List<SpaceModelVO> parentSpaceModelList = querySpaceModelParent(spaceModel.getId());

        //根据层级进行分组
        Map<Integer, SpaceModelVO> parentSpaceModelMap = parentSpaceModelList.stream().collect(Collectors.toMap(
                SpaceModelVO::getLevel,
                spaceModelVO -> spaceModelVO
        ));

        /**
         * 当level=1时模型是楼栋模型
         * 当level=2时模型是楼层模型
         * 当level=3时模型是房间模型
         * 当level=4时模型是点位模型
         */
        spaceModel.setBuildingId(parentSpaceModelMap.get(1) == null ? null : parentSpaceModelMap.get(1).getId());
        spaceModel.setBuildingName(parentSpaceModelMap.get(1) == null ? null : parentSpaceModelMap.get(1).getModelName());

        spaceModel.setFloorId(parentSpaceModelMap.get(2) == null ? null : parentSpaceModelMap.get(2).getId());
        spaceModel.setFloorName(parentSpaceModelMap.get(2) == null ? null : parentSpaceModelMap.get(2).getModelName());

        spaceModel.setRoomId(parentSpaceModelMap.get(3) == null ? null : parentSpaceModelMap.get(3).getId());
        spaceModel.setRoomName(parentSpaceModelMap.get(3) == null ? null : parentSpaceModelMap.get(3).getModelName());

        spaceModel.setPointId(parentSpaceModelMap.get(4) == null ? null : parentSpaceModelMap.get(4).getId());
        spaceModel.setPointName(parentSpaceModelMap.get(4) == null ? null : parentSpaceModelMap.get(4).getModelName());
    }

    /**
     * 修改空间模型
     */
    @Transactional
    public String updateSpaceModel(SpaceModelDTO spaceModelDTO){

        //将SpaceModelDTO类型数据转为 SpaceModel 类型
        SpaceModel spaceModel = Convert.convert(SpaceModel.class, spaceModelDTO);

        //修改模型
        super.updateById(spaceModel);

        return "修改成功";
    }

    /**
     * 删除空间模型
     */
    @Transactional
    public String deleteSpaceModel(Long id){

        //查询空间模型是否存在
        SpaceModel spaceModel = super.getById(id);

        //查询当前节点下的所有子节点数量
        Integer count = super.lambdaQuery().eq(SpaceModel::getParentId, id).count();

        //判断当前节点子节点数量是否为空
        if (count > 0){
            throw new RuntimeException(String.format("当前节点【%s】下存在子节点,请先删除子节点后再删除当前节点",spaceModel.getModelName()));
        }

        //判断查询到的模型是否为空
        if (ObjectUtils.isEmpty(spaceModel)){
            throw new RuntimeException("该模型不存在,请刷新后重试");
        }

        //存在该模型,执行删除
        super.removeById(id);

        return "删除成功";
    }


    /**
     * @param paths 根据paths精确查询
     * @return
     */
    public SpaceModel querySpaceModelByPaths(String paths){
        LambdaQueryWrapper<SpaceModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SpaceModel::getPaths, paths);
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * @param paths 查询paths下的楼层
     * @return
     */
    public List<SpaceModel> querySpaceModelLikePaths(String paths){
        LambdaQueryWrapper<SpaceModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(SpaceModel::getPaths, paths);
        // 楼层
        queryWrapper.eq(SpaceModel::getSpaceItemValue, Constants.THREE_STR);
        return baseMapper.selectList(queryWrapper);
    }

    /**
     * 查询空间模型树
     */
    public List<SpaceModel> querySpaceModelTree(SpaceModelDTO spaceModelDTO){

        //查询所有的模型
        List<SpaceModel> allSpaceModelList = baseMapper.querySpaceModelList(spaceModelDTO);

        //取出空间模型的列表中的文件id 组成文件id集合
        List<String> modelFileIdList = allSpaceModelList
                .stream()//转成stream流
                .map(SpaceModel::getModelFile)//将每个对象的modelFile属性取出,并返回
                .flatMap(modelFileId -> StrUtil.split(modelFileId, ",", -1, true, true).stream())//对modelFile属性进行扁平化处理,调用StrUtil.split进行字符串分隔,忽略空的modelFile,最后将其转换为stream流返回
                .collect(Collectors.toList());//将stream流收集,返回 modelFileIdList

        //判断文件id集合是否为空
        if (!ObjectUtils.isEmpty(modelFileIdList)){

            //若文件id集合不为空
            //通过文件id集合查询大屏文件集合
            List<LargeScreenFileVO> largeScreenFileList = largeScreenBaseMapper.queryLargeScreenFileList(modelFileIdList);

            //把文件集合设置到每个模型对象中
            allSpaceModelList.forEach(largeScreenDeviceModelVO -> {
                largeScreenFileList.forEach(largeScreenFileVO -> {
                    //先对模型文件id是否为空进行判断 再判断模型文件id是否包含 文件列表中的文件的id
                    if (largeScreenDeviceModelVO.getModelFile() != null && largeScreenDeviceModelVO.getModelFile().contains(largeScreenFileVO.getId())){
                        largeScreenDeviceModelVO.getFileList().add(largeScreenFileVO);
                    }
                });
            });
        }

        //查询最小的父节点id
        Long minParentId = allSpaceModelList.stream().map(SpaceModel::getParentId).sorted((o1, o2) -> Long.compare(o1,o2)).findFirst().orElse(null);

        //构建模型树
        return getChildren(minParentId,allSpaceModelList);
    }

    /**
     * 循环遍历获取模型树的子节点
     */
    public static List<SpaceModel> getChildren(Long parentId,List<SpaceModel> spaceModelList){

        //获取parentId为当前父节点id的那些节点
        List<SpaceModel> children = spaceModelList.stream().filter(c -> Objects.equals(c.getParentId(), parentId)).collect(Collectors.toList());

        //若子节点为空则直接返回一个空的list集合
        if (ObjectUtils.isEmpty(children)){
            return new ArrayList<>();
        }

        //遍历子节点集合
        children.forEach(c ->{

            //获取该节点的父id
            Long pId = c.getId();

            //递归获取该节点下的子节点
            List<SpaceModel> cList = getChildren(pId, spaceModelList);

            //将当前节点下所有子节点设置到当前节点中
            c.getChildren().addAll(cList);
        });

        //返回当前节点的子节点
        return children;
    }

    //父查子
    public List<SpaceModelVO> querySpaceModelChildren(Long id){
        return baseMapper.querySpaceModelChildren(id);
    }

    //子查父
    public List<SpaceModelVO> querySpaceModelParent(Long id){
        return baseMapper.querySpaceModelParent(id);
    }

    /**
     * 分页查询模型列表
     */
    public Page<SpaceModelVO> querySpaceModelListByPaging(SpaceModelQuery spaceModelQuery){

        //创建分页对象
        Page<SpaceModelVO> page = new Page<>(spaceModelQuery.getPageNum(),spaceModelQuery.getPageSize());

        //查询模型列表
        List<SpaceModelVO> spaceModelList = baseMapper.querySpaceModelListByPaging(page, spaceModelQuery);

        //将查询结果设置到分页中
        page.setRecords(spaceModelList);

        //返回分页结果
        return page;
    }
}
